/*

* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Smart-Shop开源商城系统/ Java商城-首选电商平台系统 请务必保留此注释头信息
* |     开源地址: https://gitee.com/ningbo-qishan/gruul-mall
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     可正常分享和学习源码,未经授权 不可商用！
* |     商业版中台购买/开源版商业授权 联系技术客服
* |     官网:  https://www.73app.cn/
* ------------------------------------------------------------------------
* ------------------------------------------------------------------------
* |     Copyright (c) 2016-2999 宁波启山智软科技有限公司
* |     版权所有 ,侵权必究！
* ------------------------------------------------------------------------

*/
package com.medusa.gruul.platform.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.MailAccount;
import cn.hutool.extra.mail.MailUtil;
import com.alibaba.fastjson.JSON;
import com.aliyuncs.CommonRequest;
import com.aliyuncs.CommonResponse;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.exceptions.ClientException;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.medusa.gruul.common.core.constant.CommonConstants;
import com.medusa.gruul.common.core.constant.enums.AuthCodeEnum;
import com.medusa.gruul.common.core.exception.ServiceException;
import com.medusa.gruul.common.core.util.CurUserUtil;
import com.medusa.gruul.common.core.util.LocalDateTimeUtils;
import com.medusa.gruul.common.core.util.PageUtils;
import com.medusa.gruul.common.core.util.SystemCode;
import com.medusa.gruul.common.core.validator.ValidatorUtils;
import com.medusa.gruul.common.core.validator.group.AddGroup;
import com.medusa.gruul.common.data.tenant.TenantContextHolder;
import com.medusa.gruul.common.dto.CurUserDto;
import com.medusa.gruul.platform.api.entity.AccountInfo;
import com.medusa.gruul.platform.api.entity.AgentInfo;
import com.medusa.gruul.platform.api.entity.AgentVerify;
import com.medusa.gruul.platform.conf.PlatformRedis;
import com.medusa.gruul.platform.constant.RedisConstant;
import com.medusa.gruul.platform.mapper.AgentVerifyMapper;
import com.medusa.gruul.platform.model.dto.CardBankDto;
import com.medusa.gruul.platform.model.dto.CodeEmailConfDto;
import com.medusa.gruul.platform.model.dto.agent.AgenInfoDto;
import com.medusa.gruul.platform.model.dto.agent.AgentApplyDto;
import com.medusa.gruul.platform.model.dto.agent.ListVerifyOptionDto;
import com.medusa.gruul.platform.model.dto.agent.MerchantsApplyAgentDto;
import com.medusa.gruul.platform.model.vo.CodeEmailConfVo;
import com.medusa.gruul.platform.model.vo.ListVerifyVo;
import com.medusa.gruul.platform.service.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 代理申请审核表 服务实现类
 * </p>
 *
 * @author whh
 * @since 2020-10-04
 */
@Service
public class AgentVerifyServiceImpl extends ServiceImpl<AgentVerifyMapper, AgentVerify> implements IAgentVerifyService {


    @Autowired
    private IAgentInfoService agentInfoService;
    @Autowired
    private ISendCodeService sendCodeService;
    @Autowired
    private IAccountInfoService accountInfoService;
    @Autowired
    private ISystemConfService systemConfService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void agentApply(AgentApplyDto applyDto) {
        AgentInfo agentInfo = agentInfoService.getByAccount(applyDto.getPhone());
        if (agentInfo != null) {
            throw new ServiceException("该手机号已被使用无法申请");
        }
        AgentVerify verify = this.baseMapper.selectOne(new QueryWrapper<AgentVerify>().eq("phone", applyDto.getPhone()).eq("status", CommonConstants.NUMBER_ZERO));
        if (verify != null) {
            throw new ServiceException("账号正在审核中，请勿重复提交");
        }
        verify = BeanUtil.toBean(applyDto, AgentVerify.class);
        verify.setRegisterType(CommonConstants.NUMBER_TWO);
        if (!applyDto.getIsInternal()) {
            sendCodeService.certificateCheck(applyDto.getCertificate(), applyDto.getPhone(), AuthCodeEnum.AGENT_APPLYFOR.getType());
            verify.setRegisterType(CommonConstants.NUMBER_ONE);
            verify.setAccountId(applyDto.getAccountId());
        }
        List<AgentVerify> verifies = this.list(new QueryWrapper<AgentVerify>().eq("phone", applyDto.getPhone()));
        if (CollectionUtil.isNotEmpty(verifies)) {
            DateTime dateTime = DateUtil.beginOfDay(new Date());
            List<AgentVerify> collect = verifies.stream().filter(obj -> LocalDateTimeUtils.getMilliByTime(obj.getCreateTime()) >= dateTime.getTime()).collect(Collectors.toList());
            if (CollectionUtil.isNotEmpty(collect)) {
                throw new ServiceException("一天只能申请一次，请勿重复申请");
            }
        }
        verify.setStatus(CommonConstants.NUMBER_ZERO);
        verify.setCode(getCode());
        this.save(verify);
        CodeEmailConfVo codeEmailConf = systemConfService.getCodeEmailConf();
        //邮件通知
        try {
            List<CodeEmailConfDto.EmailCode> emailNotify = codeEmailConf.getEmailNotify();
            if (CollectionUtil.isNotEmpty(emailNotify)) {
                CodeEmailConfDto.EmailCode emailCode = emailNotify.get(RandomUtil.randomInt(0, emailNotify.size()));
                //发送邮件通知
                MailAccount account = new MailAccount();
                account.setHost(emailCode.getHost());
                account.setPort(Integer.valueOf(emailCode.getPort()));
                account.setAuth(true);
                account.setSslEnable(true);
                account.setFrom(emailCode.getEmail());
                account.setPass(emailCode.getAuthCode());
                MailUtil.send(account, codeEmailConf.getEmails(),
                        "代理注册申请", "您好,你有一条新的代理申请认证信息，请及时处理！", false);
            }
        } catch (Exception e) {
            e.printStackTrace();
            log.error("邮件通知失败");
        }
        //阿里云短信通知
        if (CollectionUtil.isNotEmpty(codeEmailConf.getCodePhones())) {
            codeNotify(codeEmailConf);
        }
    }

    /**
     * 短信通知
     *
     * @param codeEmailConf com.medusa.gruul.platform.model.vo.CodeEmailConfVo
     */
    private void codeNotify(CodeEmailConfVo codeEmailConf) {
        String accessKeyId = codeEmailConf.getAccessKeyId();
        String accessKeySecret = codeEmailConf.getAccessKeySecret();
        if (StrUtil.isEmpty(accessKeyId) || StrUtil.isEmpty(accessKeySecret)) {
            return;
        }
        List<String> signNameJson = new ArrayList<>();
        for (String codePhone : codeEmailConf.getCodePhones()) {
            signNameJson.add("布谷鸟");
        }
        DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, accessKeySecret);
        IAcsClient client = new DefaultAcsClient(profile);
        CommonRequest request = new CommonRequest();
        request.setSysMethod(MethodType.POST);
        request.setSysDomain("dysmsapi.aliyuncs.com");
        request.setSysVersion("2017-05-25");
        request.setSysAction("SendBatchSms");
        request.putQueryParameter("RegionId", "cn-hangzhou");
        request.putQueryParameter("PhoneNumberJson", JSON.toJSONString(codeEmailConf.getCodePhones()));
        request.putQueryParameter("SignNameJson", JSON.toJSONString(signNameJson));
        request.putQueryParameter("TemplateCode", codeEmailConf.getTemplateCode());
        try {
            CommonResponse response = client.getCommonResponse(request);
            System.out.println(response.getData());
        } catch (ClientException e) {
            e.printStackTrace();
            log.error("短信通知失败");
        }
    }


    @Override
    public String getCode() {
        String code = RandomUtil.randomString(6);
        int i = 1;
        //确保code未生成才可使用
        while (i != 1) {
            AgentVerify exit = this.getByCode(code);
            if (exit == null) {
                int count = agentInfoService.count(new QueryWrapper<AgentInfo>().eq("code", code));
                if (count == 0) {
                    i = 0;
                }
            }
            code = RandomUtil.randomString(6);
        }
        return code;
    }

    /**
     * 查询未审核和审核通过中,已存在的邀请码数据
     *
     * @param code 邀请码
     * @return com.medusa.gruul.platform.api.entity.AgentVerify
     */
    private AgentVerify getByCode(String code) {
        return this.getOne(new QueryWrapper<AgentVerify>().eq("code", code).in("status", Arrays.asList(CommonConstants.NUMBER_ZERO, CommonConstants.NUMBER_ONE)));
    }

    @Override
    public PageUtils<ListVerifyVo> listVerify(Integer page, Integer size, Integer status, String startTime, String endTime, String search,
                                              String refusedStartTime, String refusedEndTime) {

        IPage<AgentVerify> pageInfos = this.baseMapper.selectByListVerify(new Page<>(page, size), status, startTime, endTime, search, refusedStartTime, refusedEndTime);
        if (CollectionUtil.isEmpty(pageInfos.getRecords())) {
            return new PageUtils(pageInfos);
        }
        List<ListVerifyVo> collect = pageInfos.getRecords().stream().map(obj -> BeanUtil.toBean(obj, ListVerifyVo.class)).collect(Collectors.toList());
        return new PageUtils(collect, (int) pageInfos.getTotal(), (int) pageInfos.getSize(), (int) pageInfos.getCurrent());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void listVerifyOption(ListVerifyOptionDto optionDto) {
        ValidatorUtils.validateEntity(optionDto);
        AgentVerify agentVerify = this.getById(optionDto.getId());
        if (agentVerify == null) {
            throw new ServiceException("无效的审核数据");
        }
        if (!agentVerify.getStatus().equals(CommonConstants.NUMBER_ZERO)) {
            throw new ServiceException("该申请不在审核状态");
        }
        //拒绝
        if (optionDto.getOptionType().equals(CommonConstants.NUMBER_ONE)) {
            agentVerify.setStatus(CommonConstants.NUMBER_TWO);
            this.updateById(agentVerify);
            //商户注册
            if (agentVerify.getRegisterType().equals(CommonConstants.NUMBER_TWO)) {
                PlatformRedis platformRedis = new PlatformRedis();
                platformRedis.del(RedisConstant.MERCHANTS_APPLY_AGENT_LIMIT.concat(agentVerify.getAccountId().toString()));
            }
            return;
        }
        AgenInfoDto agenInfoDto = optionDto.getAgenInfoDto();
        ValidatorUtils.validateEntity(agenInfoDto, AddGroup.class);
        agenInfoDto.validate();
        if (agentInfoService.getByAccount(agenInfoDto.getAccount()) != null) {
            throw new ServiceException("账号已存在");
        }
        CardBankDto bankInfo = agenInfoDto.getBankInfo();
        sendCodeService.certificateCheck(bankInfo.getCertificate(), bankInfo.getCardPhone(), AuthCodeEnum.AGENT_BANK_VALIDATE.getType());
        //审核通过
        agentVerify.setStatus(CommonConstants.NUMBER_ONE);
        this.updateById(agentVerify);
        agenInfoDto.setEnterprise(agentVerify.getEnterprise());
        agenInfoDto.setEnterpriseType(agentVerify.getEnterpriseType());
        agenInfoDto.setScaleCode(agentVerify.getScaleCode());
        Long agentId = agentInfoService.newAccount(agenInfoDto, agentVerify.getCode(), agentVerify.getRegisterType());
        if (agentVerify.getRegisterType().equals(CommonConstants.NUMBER_TWO)) {
            AccountInfo accountInfo = new AccountInfo();
            accountInfo.setMeAgentId(agentId);
            accountInfo.setId(agentVerify.getAccountId());
            accountInfoService.updateById(accountInfo);
        }
    }

    @Override
    public ListVerifyVo getByIdVo(Long id) {
        AgentVerify agentVerify = this.getById(id);
        if (agentVerify == null) {
            throw new ServiceException("不存在指定表数据");
        }
        return BeanUtil.toBean(agentVerify, ListVerifyVo.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void merchantsApplyAgent(MerchantsApplyAgentDto applyAgentDto) {
        PlatformRedis platformRedis = new PlatformRedis();
        CurUserDto curUser = CurUserUtil.getHttpCurUser();
        if (curUser == null) {
            throw new ServiceException("非法查询", SystemCode.DATA_NOT_EXIST.getCode());
        }
        String redisKey = RedisConstant.MERCHANTS_APPLY_AGENT_LIMIT.concat(curUser.getUserId());
        String exit = platformRedis.get(redisKey);
        if (StrUtil.isNotEmpty(exit)) {
            throw new ServiceException("请勿重复申请，等待审核结果");
        }
        AgentApplyDto applyDto = BeanUtil.toBean(applyAgentDto, AgentApplyDto.class);
        String tenantId = TenantContextHolder.getTenantId();
        if (StrUtil.isEmpty(tenantId)) {
            throw new ServiceException("无效操作");
        }
        AccountInfo accountInfo = accountInfoService.getById(curUser.getUserId());
        applyDto.setLinkName(accountInfo.getNikeName());
        applyDto.setPhone(accountInfo.getPhone());
        applyDto.setRegion(accountInfo.getRegion());
        applyDto.setAddress(accountInfo.getAddress());
        applyDto.setIsInternal(Boolean.TRUE);
        applyDto.setAccountId(accountInfo.getId());
        this.agentApply(applyDto);
        Date date = new Date();
        platformRedis.setNxPx(redisKey, "1", DateUtil.betweenMs(date, DateUtil.endOfDay(date)));
    }

    @Override
    public void deleteVerify(Long id) {
        AgentVerify agentVerify = this.getById(id);
        if (agentVerify == null) {
            throw new ServiceException("不存在所属记录");
        }
        if (!agentVerify.getStatus().equals(CommonConstants.NUMBER_TWO)) {
            throw new ServiceException("数据状态异常");
        }
        this.baseMapper.deleteById(id);
    }

}
